﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenTK.Graphics.ES30;


namespace ttbit.Windows
{
    public class GLWin : IGL.ITTGL
    {
        public void ActiveTexture(IGL.TextureUnit texturunit)
        {
            GL.ActiveTexture((TextureUnit)texturunit);
        }

        public void BindBuffer(IGL.BufferTarget traget, int bufid)
        {
            GL.BindBuffer((BufferTarget)traget, bufid);
        }

        public void BindFrameBuffer(int fboid)
        {
            GL.BindFramebuffer(FramebufferTarget.Framebuffer, fboid);
        }

        public void BindSampler(int unit, int sampler)
        {
            GL.BindSampler(unit, sampler);
        }

        public void BindTexture2D(int texid)
        {
            GL.BindTexture(TextureTarget.Texture2D, texid);
        }

        public void BindVertexArray(int vaoid)
        {
            GL.BindVertexArray(vaoid);
        }

        public void BlendEquation(IGL.BlendEquationMode mode)
        {
            GL.BlendEquation((BlendEquationMode)mode);
        }

        public void BlendEquationSeparate(IGL.BlendEquationMode modeRGB, IGL.BlendEquationMode modeAlpha)
        {
            GL.BlendEquationSeparate((BlendEquationMode)modeRGB, (BlendEquationMode)modeAlpha);
        }

        public void BlendFunc(IGL.BlendingFactorSrc sfactor, IGL.BlendingFactorDest dfactor)
        {
            GL.BlendFunc((BlendingFactorSrc)sfactor, (BlendingFactorDest)dfactor);
        }

        public void BlendFuncSeparate(IGL.BlendingFactorSrc srcRGB, IGL.BlendingFactorDest dstRGB, IGL.BlendingFactorSrc srcAlpha, IGL.BlendingFactorDest dstAlpha)
        {
            GL.BlendFuncSeparate((BlendingFactorSrc)srcRGB, (BlendingFactorDest)dstRGB, (BlendingFactorSrc)srcAlpha, (BlendingFactorDest)dstAlpha);
        }

        public void BufferData<T>(IGL.BufferTarget traget, int count, T[] buffers, IGL.BufferUsage usage) where T : struct
        {
            GL.BufferData((BufferTarget)traget, count, buffers, (BufferUsageHint)usage);
        }

        public void BufferData(IGL.BufferTarget traget, int count, IntPtr buffers, IGL.BufferUsage usage)
        {
            GL.BufferData((BufferTarget)traget, count, buffers, (BufferUsageHint)usage);
        }

        public unsafe void BufferData(IGL.BufferTarget traget, int count, byte* buffers, IGL.BufferUsage usage)
        {
            GL.BufferData((BufferTarget)traget, count, (IntPtr)buffers, (BufferUsageHint)usage);
        }

        public void Clear(IGL.ClearFlag flag = IGL.ClearFlag.ColorBufferBit)
        {
            GL.Clear((ClearBufferMask)flag);
        }

        public void ClearColor(float r, float g, float b, float a)
        {
            GL.ClearColor(r, g, b, a);
        }

        public bool CompileShader(int shaderid, string code)
        {
            GL.ShaderSource(shaderid, code);
            GL.CompileShader(shaderid);
            GL.GetShader(shaderid, ShaderParameter.CompileStatus, out int p);
            return p > 0;
        }

        public int CreateFrameBuffer()
        {
            GL.GenFramebuffers(1, out int fbo);
            return fbo;
        }

        public int CreateProgram()
        {
            return GL.CreateProgram();
        }

        public int CreateSampler()
        {
            GL.GenSamplers(1, out int s);
            return s;
        }

        public int CreateShader(IGL.ShaderType type)
        {
            return GL.CreateShader((ShaderType)type);
        }

        public int CreateTexture()
        {
            return GL.GenTexture();
        }

        public void ReadPixels<T>(int x, int y, int width, int height, IGL.TextureType format, T[] buf) where T : struct
        {
            bool gray = format <= IGL.TextureType.R_Float;
            //PixelInternalFormat glformat = gray ? PixelInternalFormat.Luminance : PixelInternalFormat.Rgba;
            TextureComponentCount glformat = gray ? TextureComponentCount.Luminance : TextureComponentCount.Rgba;
            OpenTK.Graphics.ES30.PixelFormat pformat = gray ? OpenTK.Graphics.ES30.PixelFormat.Luminance : OpenTK.Graphics.ES30.PixelFormat.Rgba;
            PixelType pixeltype = PixelType.UnsignedByte;
            if (format == IGL.TextureType.R_HalfFloat || format == IGL.TextureType.RGBA_HalfFloat)
                pixeltype = PixelType.HalfFloat;
            else if (format == IGL.TextureType.RGBA_Float || format == IGL.TextureType.R_Float)
                pixeltype = PixelType.Float;


            GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
            GL.ReadPixels<T>(x, y, width, height, pformat, pixeltype, buf);
        }
        public void DeleteBuffer(int bufid)
        {
            uint bufs = (uint)bufid;
            GL.DeleteBuffers(1, ref bufs);
        }

        public void DeleteFrameBuffer(int fboid)
        {
            GL.DeleteFramebuffers(1, ref fboid);
        }

        public void DeleteProgram(int progid)
        {
            GL.DeleteProgram(progid);
        }

        public void DeleteSampler(int sampler)
        {
            GL.DeleteSamplers(1, ref sampler);
        }

        public void DeleteShader(int shaderid)
        {
            GL.DeleteShader(shaderid);
        }

        public void DeleteTexture(int texid)
        {
            GL.DeleteTexture(texid);
        }

        public void DeleteVertexArray(int vaoid)
        {
            GL.DeleteVertexArrays(1, ref vaoid);
        }

        public void Disable(IGL.EnableCap cap)
        {
            GL.Disable((EnableCap)cap);
        }

        public void DrawArrays(IGL.BeginMode mode, int first, int vcount)
        {
            GL.DrawArrays((PrimitiveType)mode, first, vcount);
        }

        public void DrawElements(IGL.BeginMode mode, int ebocount, IGL.DrawElementsType type, IntPtr indices)
        {
            GL.DrawElements((PrimitiveType)mode, ebocount, (DrawElementsType)type, indices);
        }

        public void Enable(IGL.EnableCap cap)
        {
            GL.Enable((EnableCap)cap);
        }

        public void EnableVertexAttribArray(int index)
        {
            GL.EnableVertexAttribArray(index);
        }

        public void FrameBufferTexture2D(IGL.FrameBufferSlot slot, int texid, int level)
        {
            GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, (FramebufferAttachment)slot, TextureTarget2d.Texture2D, texid, level);
        }

        public int GenBuffer()
        {
            GL.GenBuffers(1, out int bufid);
            return bufid;
        }

        public int GenVertexArray()
        {
            GL.GenVertexArrays(1, out int vaoid);
            return vaoid;
        }

        public int GetAttribLocation(int progid, string name)
        {
            return GL.GetAttribLocation(progid, name);
        }

        public string GetProgramInfoLog(int progid)
        {
            return GL.GetProgramInfoLog(progid);
        }

        public string GetShaderInfoLog(int shaderid)
        {
            return GL.GetShaderInfoLog(shaderid);
        }

        public int GetUniformLocation(int progid, string name)
        {
            return GL.GetUniformLocation(progid, name);
        }

        public string GetVersion()
        {
            return GL.GetString(StringName.Version);
        }

        public bool LinkProgram(int progid, int vsid, int fsid)
        {
            GL.AttachShader(progid, vsid);
            GL.AttachShader(progid, fsid);
            GL.LinkProgram(progid);
            GL.GetProgram(progid, GetProgramParameterName.LinkStatus, out int v);
            return v > 0;
        }

        public void SamplerParameter(int sampler, IGL.SamplerParameterName name, IGL.SamplerValue value)
        {
            GL.SamplerParameter(sampler, (SamplerParameterName)name, (int)value);
        }

        public void TexImage2D(int level, IGL.TextureType format, int width, int height)
        {
            bool gray = format <= IGL.TextureType.R_Float;
            //PixelInternalFormat glformat = gray ? PixelInternalFormat.Luminance : PixelInternalFormat.Rgba;
            TextureComponentCount glformat = gray ? TextureComponentCount.Luminance : TextureComponentCount.Rgba;
            OpenTK.Graphics.ES30.PixelFormat pformat = gray ? OpenTK.Graphics.ES30.PixelFormat.Luminance : OpenTK.Graphics.ES30.PixelFormat.Rgba;
            PixelType pixeltype = PixelType.UnsignedByte;
            if (format == IGL.TextureType.R_HalfFloat || format == IGL.TextureType.RGBA_HalfFloat)
                pixeltype = PixelType.HalfFloat;
            else if (format == IGL.TextureType.RGBA_Float || format == IGL.TextureType.R_Float)
                pixeltype = PixelType.Float;

            GL.TexImage2D(TextureTarget2d.Texture2D, level, glformat, width, height, 0, pformat, pixeltype, IntPtr.Zero);
        }

        public void TexImage2D<T>(int level, IGL.TextureType format, int width, int height, T[] data) where T : struct
        {
            bool gray = format <= IGL.TextureType.R_Float;
            //PixelInternalFormat glformat = gray ? PixelInternalFormat.Luminance : PixelInternalFormat.Rgba;
            TextureComponentCount glformat = gray ? TextureComponentCount.Luminance : TextureComponentCount.Rgba;
            OpenTK.Graphics.ES30.PixelFormat pformat = gray ? OpenTK.Graphics.ES30.PixelFormat.Luminance : OpenTK.Graphics.ES30.PixelFormat.Rgba;
            PixelType pixeltype = PixelType.UnsignedByte;
            if (format == IGL.TextureType.R_HalfFloat || format == IGL.TextureType.RGBA_HalfFloat)
                pixeltype = PixelType.HalfFloat;
            else if (format == IGL.TextureType.RGBA_Float || format == IGL.TextureType.R_Float)
                pixeltype = PixelType.Float;

            GL.TexImage2D(TextureTarget2d.Texture2D, level, glformat, width, height, 0, pformat, pixeltype, data);
        }

        public void TexImage2D(int level, IGL.TextureType format, int width, int height, IntPtr data)
        {
            bool gray = format <= IGL.TextureType.R_Float;
            //PixelInternalFormat glformat = gray ? PixelInternalFormat.Luminance : PixelInternalFormat.Rgba;
            TextureComponentCount glformat = gray ? TextureComponentCount.Luminance : TextureComponentCount.Rgba;
            OpenTK.Graphics.ES30.PixelFormat pformat = gray ? OpenTK.Graphics.ES30.PixelFormat.Luminance : OpenTK.Graphics.ES30.PixelFormat.Rgba;
            PixelType pixeltype = PixelType.UnsignedByte;
            if (format == IGL.TextureType.R_HalfFloat || format == IGL.TextureType.RGBA_HalfFloat)
                pixeltype = PixelType.HalfFloat;
            else if (format == IGL.TextureType.RGBA_Float || format == IGL.TextureType.R_Float)
                pixeltype = PixelType.Float;

            GL.TexImage2D(TextureTarget2d.Texture2D, level, glformat, width, height, 0, pformat, pixeltype, data);
        }

        public unsafe void TexImage2D(int level, IGL.TextureType format, int width, int height, byte* data)
        {
            bool gray = format <= IGL.TextureType.R_Float;
            //PixelInternalFormat glformat = gray ? PixelInternalFormat.Luminance : PixelInternalFormat.Rgba;
            TextureComponentCount glformat = gray ? TextureComponentCount.Luminance : TextureComponentCount.Rgba;
            OpenTK.Graphics.ES30.PixelFormat pformat = gray ? OpenTK.Graphics.ES30.PixelFormat.Luminance : OpenTK.Graphics.ES30.PixelFormat.Rgba;
            PixelType pixeltype = PixelType.UnsignedByte;
            if (format == IGL.TextureType.R_HalfFloat || format == IGL.TextureType.RGBA_HalfFloat)
                pixeltype = PixelType.HalfFloat;
            else if (format == IGL.TextureType.RGBA_Float || format == IGL.TextureType.R_Float)
                pixeltype = PixelType.Float;

            GL.TexImage2D(TextureTarget2d.Texture2D, level, glformat, width, height, 0, pformat, pixeltype, (IntPtr)data);
        }

        public void TexSubImage2D<T>(int level, IGL.TextureType format, int xoffset, int yoffset, int width, int height, T[] data) where T : struct
        {
            bool gray = format <= IGL.TextureType.R_Float;
            OpenTK.Graphics.ES30.PixelFormat pformat = gray ? OpenTK.Graphics.ES30.PixelFormat.Luminance : OpenTK.Graphics.ES30.PixelFormat.Rgba;
            PixelType pixeltype = PixelType.UnsignedByte;
            if (format == IGL.TextureType.R_HalfFloat || format == IGL.TextureType.RGBA_HalfFloat)
                pixeltype = PixelType.HalfFloat;
            else if (format == IGL.TextureType.RGBA_Float || format == IGL.TextureType.R_Float)
                pixeltype = PixelType.Float;

            GL.TexSubImage2D(TextureTarget2d.Texture2D, level, xoffset, yoffset, width, height, pformat, pixeltype, data);
        }

        public void TexSubImage2D(int level, IGL.TextureType format, int xoffset, int yoffset, int width, int height, IntPtr data)
        {
            bool gray = format <= IGL.TextureType.R_Float;
            OpenTK.Graphics.ES30.PixelFormat pformat = gray ? OpenTK.Graphics.ES30.PixelFormat.Luminance : OpenTK.Graphics.ES30.PixelFormat.Rgba;
            PixelType pixeltype = PixelType.UnsignedByte;
            if (format == IGL.TextureType.R_HalfFloat || format == IGL.TextureType.RGBA_HalfFloat)
                pixeltype = PixelType.HalfFloat;
            else if (format == IGL.TextureType.RGBA_Float || format == IGL.TextureType.R_Float)
                pixeltype = PixelType.Float;

            GL.TexSubImage2D(TextureTarget2d.Texture2D, level, xoffset, yoffset, width, height, pformat, pixeltype, data);
        }

        public unsafe void TexSubImage2D<T>(int level, IGL.TextureType format, int xoffset, int yoffset, int width, int height, byte* data)
        {
            bool gray = format <= IGL.TextureType.R_Float;
            OpenTK.Graphics.ES30.PixelFormat pformat = gray ? OpenTK.Graphics.ES30.PixelFormat.Luminance : OpenTK.Graphics.ES30.PixelFormat.Rgba;
            PixelType pixeltype = PixelType.UnsignedByte;
            if (format == IGL.TextureType.R_HalfFloat || format == IGL.TextureType.RGBA_HalfFloat)
                pixeltype = PixelType.HalfFloat;
            else if (format == IGL.TextureType.RGBA_Float || format == IGL.TextureType.R_Float)
                pixeltype = PixelType.Float;

            GL.TexSubImage2D(TextureTarget2d.Texture2D, level, xoffset, yoffset, width, height, pformat, pixeltype, (IntPtr)data);
        }

        public void Uniform1f(int uniid, float v)
        {
            GL.Uniform1(uniid, v);
        }



        public unsafe void Uniform1f(int uniid, int count, float* v)
        {
            GL.Uniform1(uniid, count, v);
        }

        public void Uniform1i(int uniid, int v)
        {
            GL.Uniform1(uniid, v);
        }

        public unsafe void Uniform1i(int uniid, int count, int* v)
        {
            GL.Uniform1(uniid, count, v);
        }

        public void Uniform2f(int uniid, float x, float y)
        {
            GL.Uniform2(uniid, x, y);
        }

        public unsafe void Uniform2f(int uniid, int count, float* v)
        {
            GL.Uniform2(uniid, count, v);
        }

        public void Uniform2i(int uniid, int x, int y)
        {
            GL.Uniform2(uniid, x, y);
        }

        public unsafe void Uniform2i(int uniid, int count, int* v)
        {
            GL.Uniform2(uniid, count, v);
        }

        public void Uniform3f(int uniid, float x, float y, float z)
        {
            GL.Uniform3(uniid, x, y, z);
        }

        public unsafe void Uniform3f(int uniid, int count, float* v)
        {
            GL.Uniform3(uniid, count, v);
        }

        public void Uniform3i(int uniid, int x, int y, int z)
        {
            GL.Uniform3(uniid, x, y, z);
        }

        public unsafe void Uniform3i(int uniid, int count, int* v)
        {
            GL.Uniform3(uniid, count, v);
        }

        public void Uniform4f(int uniid, float x, float y, float z, float w)
        {
            GL.Uniform4(uniid, x, y, z, w);
        }

        public unsafe void Uniform4f(int uniid, int count, float* v)
        {
            GL.Uniform4(uniid, count, v);
        }

        public void Uniform4i(int uniid, int x, int y, int z, int w)
        {
            GL.Uniform4(uniid, x, y, z, w);
        }

        public unsafe void Uniform4i(int uniid, int count, int* v)
        {
            GL.Uniform4(uniid, count, v);
        }

        public void UniformMatrix2(int uniid, int count, bool transpose, float[] v)
        {
            GL.UniformMatrix2(uniid, count, transpose, v);
        }

        public unsafe void UniformMatrix2(int uniid, int count, bool transpose, float* v)
        {
            GL.UniformMatrix2(uniid, count, transpose, v);
        }

        public void UniformMatrix2x3(int uniid, int count, bool transpose, float[] v)
        {
            GL.UniformMatrix2x3(uniid, count, transpose, v);
        }
        public unsafe void UniformMatrix2x3(int uniid, int count, bool transpose, float* v)
        {
            GL.UniformMatrix2x3(uniid, count, transpose, v);
        }
        public void UniformMatrix3(int uniid, int count, bool transpose, float[] v)
        {
            GL.UniformMatrix3(uniid, count, transpose, v);
        }

        public unsafe void UniformMatrix3(int uniid, int count, bool transpose, float* v)
        {
            GL.UniformMatrix3(uniid, count, transpose, v);
        }

        public void UniformMatrix4(int uniid, int count, bool transpose, float[] v)
        {
            GL.UniformMatrix4(uniid, count, transpose, v);
        }

        public unsafe void UniformMatrix4(int uniid, int count, bool transpose, float* v)
        {
            GL.UniformMatrix4(uniid, count, transpose, v);
        }

        public void UseProgram(int progid)
        {
            GL.UseProgram(progid);
        }

        public void VertexAttribPointer(int index, int size, IGL.VertexAttribPointerType type, bool normalized, int stride, int offset)
        {
            GL.VertexAttribPointer(index, size, (VertexAttribPointerType)type, normalized, stride, offset);
        }

        public void Viewport(int x, int y, int width, int height)
        {
            GL.Viewport(x, y, width, height);
        }

        public void Scissor(int x, int y, int width, int height)
        {
            GL.Scissor(x, y, width, height);
        }
    }
}